
local Element = import("./Element.lua");
local KeyBoard = import("../KeyBoard.lua");

local TextArea = commonlib.inherit(Element);
local CursorShowHideMaxTickCount = 30;

TextArea:Property("ShowCursor", false, "IsShowCursor");         -- 是否显示光标
TextArea:Property("AutoLineFeed", false, "IsAutoLineFeed");      -- 是否自动换行
TextArea:Property("DefaultStyle", "box-sizing: border-box; display: inline-block; border-width: 1px; border-color: #cccccc; color: #000000; height: 90px; font-size: 14px; line-height: 1.5; width: 200px; padding: 4px; background-color: #ffffff;");

function TextArea:ctor()
    self:SetName("TextArea");
    self.__text__ = commonlib.ustring("");
    self:Reset();
end

function TextArea:Init(xmlnode, window, parent)
    self:InitElement(xmlnode, window, parent);

    self:OnAttrValueChange("value");
    return self;
end

function TextArea:OnAttrValueChange(attrName, attrValue)
    if (attrName == "value") then
        self:SetValue(self:GetAttrStringValue(attrName));
    end
end

function TextArea:Reset()
    self.__view_max_line_count__ = 0;                                    -- 视图最大行数
    self.__offset_y_line_count__ = 0;                                  -- 纵轴偏移行
    self.__cursor_show_hide_tick_count__ = 0;
    self.__lines__ = {};                                               -- 行信息
    self.__undo_cmds__ = {};                                           -- 撤销命令
    self.__redo_cmds__ = {};                                           -- 重做命令
    self.__cursor_at__ = 1;                                            -- 光标位置索引
    self.__cursor_x__ = 0;                                             -- 光标位置
    self.__cursor_lineindex__ = 1;                                     -- 光标行
    self.__selected_start_x__, self.__selected_end_x__ = 0, 0;         -- 文本选择的位置
    self.__selected_start_y__, self.__selected_end_y__ = 0, 0;         -- 文本选择的位置
    self.__selected_start_lineindex__, self.__selected_end_lineindex__ = 0, 0;
    self.__selected_start_at__, self.__selected_end_at__ = 0, 0;       -- 文本选择
    self.__offset_x__, self.__offset_y__ = 0, 0;                       -- 横向 纵向滚动
end

function TextArea:SetValue(value)
    value = tostring(value or "");
    if (value == self.__text__:tostring()) then return end
    self.__text__ = commonlib.ustring(value);
    self:Reset();
    self:UpdateLineInfo();
end

function TextArea:GetValue()
    return self.__text__:tostring();
end

function TextArea:GetText()
    return self.__text__;
end

function TextArea:GetTextLength()
    return self.__text__:len();
end

-- 是否选择
function TextArea:IsSelected()
    return self.__selected_start_at__ > 0 and self.__selected_end_at__ > 0 and self.__selected_start_at__ ~= self.__selected_end_at__;  -- [selectStartAt, selectEndAt)
end

-- 获取选择的文本
function TextArea:GetSelectedText()
    return self.__text__:sub(self:GetSelected()):tostring();
end

-- 获取选择
function TextArea:GetSelected()
    if (not self:IsSelected()) then return 0, 0 end
    if (self.__selected_end_at__ < self.__selected_start_at__) then return self.__selected_end_at__, self.__selected_start_at__ end
    return self.__selected_start_at__, self.__selected_end_at__;
end

-- 清除选择
function TextArea:ClearSelected()
    self.__selected_start_at__, self.__selected_end_at__ = 0, 0;
    self.__selected_start_lineindex__, self.__selected_end_lineindex__ = 0, 0;
    self.__selected_start_x__, self.__selected_start_y__ = 0, 0;
    self.__selected_end_x__, self.__selected_end_y__ = 0, 0;
end

-- 更新选择位置
function TextArea:AdjustSelectedXY()
    local LineHeight = self:GetLineHeight();
    local __selected_start_line__ = self.__lines__[self.__selected_start_lineindex__];

    if (__selected_start_line__) then
        self.__selected_start_x__ = self:GetTextWidth(__selected_start_line__.__text__:sub(1, self.__selected_start_at__ - __selected_start_line__.__start_at__):tostring());
        self.__selected_start_y__ = (self.__selected_start_lineindex__ - 1) * LineHeight;
    else
        self.__selected_start_x__, self.__selected_start_y__ = 0, 0;
    end

    local __selected_end_line__ = self.__lines__[self.__selected_end_lineindex__];
    if (__selected_end_line__) then
        self.__selected_end_x__ = self:GetTextWidth(__selected_end_line__.__text__:sub(1, self.__selected_end_at__ - __selected_end_line__.__start_at__):tostring());
        self.__selected_end_y__ = (self.__selected_end_lineindex__ - 1) * LineHeight;
    else
        self.__selected_end_x__, self.__selected_end_y__ = 0, 0;
    end
end

function TextArea:UpdateLayout()
    TextArea._super.UpdateLayout(self);
    self:UpdateLineInfo();
end

-- 更新文本行信息
function TextArea:UpdateLineInfo()
    local text = self:GetValue();
    local size = self:GetTextLength();
    local delim = "\n";
    local lastLineStartAt = 1;
    local x, y, w, h = self:GetContentPosition();
    self.__lines__ = {};
    self.__view_max_line_count__ = math.floor(h / self:GetLineHeight());
    self.__view_max_width__ = w;

    if (w == 0 or h == 0) then return end

    -- print("---------------------------------TextArea:UpdateLineInfo:BEGIN---------------------------------------")
    repeat 
        local line = {};
        local startAt, endAt = string.find(text, delim, lastLineStartAt, true);
        line.__text__ = commonlib.ustring(string.sub(text, lastLineStartAt, startAt and (startAt - 1)));
        line.__start_at__ = commonlib.ustring(string.sub(text, 1, lastLineStartAt - 1)):len() + 1;
        line.__end_at__ = line.__start_at__ + line.__text__:len(); -- [__start_at__, __end_at__)
        line.__width__ = self:GetTextWidth(line.__text__:tostring());
        lastLineStartAt = endAt and (endAt + 1);
        table.insert(self.__lines__, line);
    until (not startAt or not lastLineStartAt);

    if (not self:IsAutoLineFeed()) then return end

    local linecount = #self.__lines__;
    local lineindex = 1;
    while (lineindex <= (#self.__lines__)) do
        local line = self.__lines__[lineindex]
        local linetext = line.__text__:tostring();
        local lines = {};
        local lastAt = line.__start_at__;
        repeat
            local trimtext, remaintext = self:GetTextByWidth(linetext, w);
            local __text__ = commonlib.ustring(trimtext);
            local __start_at__ = lastAt;
            local __end_at__ = lastAt + __text__:len();
            lastAt = __end_at__;    
            linetext = remaintext;
            table.insert(lines, {__text__ = __text__, __start_at__ = __start_at__, __end_at__ = __end_at__, __width__ = self:GetTextWidth(__text__:tostring())});
            -- print(__text__:tostring(), __start_at__, __end_at__, linetext)
        until(remaintext == "" or trimtext == "");
        -- 拆分
        if ((#lines) > 1) then
            table.remove(self.__lines__, lineindex);
            for _, line in ipairs(lines) do
                table.insert(self.__lines__, lineindex, line);
                lineindex = lineindex + 1;
            end
        else
            lineindex = lineindex + 1;
        end
    end
    -- print("---------------------------------TextArea:UpdateLineInfo:END---------------------------------------")
    -- commonlib.echo(self.__lines__);
end

function TextArea:RenderContent()
    local _x, _y, _w, _h = self:GetPosition();
    local x, y, w, h = self:GetContentPosition();
    local LineHeight = self:GetLineHeight();
    self:Save();
    self:DrawRectangle(x - 1, y, w + 1, h, false, false);
    self:Clip();
    self:Translate(x - self.__offset_x__, y - self.__offset_y__);

    if (self:IsSelected()) then
        self:SetBrushColor(0x3390ffff);
        local __selected_start_lineindex__, __selected_end_lineindex__ = self.__selected_start_lineindex__, self.__selected_end_lineindex__;
        local __selected_start_at__, __selected_end_at__ = self.__selected_start_at__, self.__selected_end_at__;
        local __selected_start_x__, __selected_start_y__ = self.__selected_start_x__, self.__selected_start_y__;
        local __selected_end_x__, __selected_end_y__ = self.__selected_end_x__, self.__selected_end_y__;

        if (__selected_end_at__ < __selected_start_at__) then 
            __selected_start_at__, __selected_end_at__ = __selected_end_at__, __selected_start_at__;
            __selected_start_lineindex__, __selected_end_lineindex__ = __selected_end_lineindex__, __selected_start_lineindex__; 
            __selected_start_x__, __selected_end_x__ = __selected_end_x__, __selected_start_x__;
            __selected_start_y__, __selected_end_y__ = __selected_end_y__, __selected_start_y__;
        end

        local __selected_start_line__ = self.__lines__[__selected_start_lineindex__];
        local __selected_end_line__ = self.__lines__[__selected_end_lineindex__];
        if (__selected_start_line__ and __selected_end_line__) then
            if (__selected_start_lineindex__ == __selected_end_lineindex__) then
                self:DrawRectangle(__selected_start_x__, __selected_start_y__, __selected_end_x__ - __selected_start_x__, LineHeight);
            else
                self:DrawRectangle(__selected_start_x__, __selected_start_y__, __selected_start_line__.__width__ - __selected_start_x__, LineHeight);
                for lineindex = __selected_end_lineindex__ + 1, __selected_end_lineindex__ - 1 do
                    local line = self.__lines__[lineindex];
                    self:DrawRectangle(0, (lineindex - 1) * LineHeight, line.__width__, LineHeight);
                end
                self:DrawRectangle(0, __selected_end_y__, __selected_end_x__, LineHeight);
            end
        end
    end

    self:ApplyStyleFontToPaint();
    for i, line in ipairs(self.__lines__) do
        self:DrawText(0, (i - 1) * LineHeight, w, LineHeight, line.__text__:tostring());
    end

    if (self:IsFocus()) then
        self.__cursor_show_hide_tick_count__ = self.__cursor_show_hide_tick_count__ + 1;
        if (self.__cursor_show_hide_tick_count__ > CursorShowHideMaxTickCount) then 
            self.__cursor_show_hide_tick_count__ = 0;
            self:SetShowCursor(not self:IsShowCursor());
        end
        if (self:IsShowCursor()) then
            self:SetPenColor(0xff);
            self:SetLineWidth(1);
            self:DrawLine(self.__cursor_x__, (self.__cursor_lineindex__ - 1) * LineHeight + 1, self.__cursor_x__, self.__cursor_lineindex__ * LineHeight - 1);
        end
    end

    self:Translate(-x + self.__offset_x__, -y + self.__offset_y__);
    self:Restore();
end

function TextArea:ResetCursor()
    self.__cursor_show_hide_tick_count__ = 0;
    self:SetShowCursor(true);
end

function TextArea:OnFocusIn()
    TextArea._super.OnFocusIn(self);
    self:ResetCursor();
    commonlib.StartTextInput();
end

function TextArea:OnFocusOut()
    TextArea._super.OnFocusOut(self);
    self:ClearSelected();
    commonlib.StopTextInput();
end

function TextArea:SetCursorByPos(sx, sy)
    local x, y, w, h = self:GetContentPosition();
    local vx = sx - x;   -- 视图坐标
    local vy = sy - y;
    local cursorX = vx + self.__offset_x__;
    local cursorY = vy + self.__offset_y__;
    local LineHeight = self:GetLineHeight();
    local lineindex = math.max(1, math.min(#self.__lines__, math.ceil(cursorY / LineHeight))); 
    local line = self.__lines__[lineindex];
    local text = self:GetTextByWidth(line.__text__:tostring(), cursorX);
    self.__cursor_at__ = line.__start_at__ + commonlib.ustring(text):len();
    self.__cursor_x__ = self:GetTextWidth(text);
    self.__cursor_lineindex__ = lineindex;
    -- print(string.format("lineindex = %s, cursorAt = %s", self.__cursor_lineindex__, self.__cursor_at__));
end

function TextArea:OnMouseDown(event)
    if (self:IsDisabled() or not event:IsLeftButton()) then return end
    if (not self:IsFocus()) then self:FocusIn() end
    
    local sx, sy = event:GetXY();
    self.__mouse_down__ = true;
    self:ClearSelected();
    self:SetCursorByPos(sx, sy);
    self:CaptureMouse();
    if (event:IsTripleClick()) then
        self:HandleSelectAll();
    elseif (event:IsDoubleClick()) then
        self:handleSelectWorld();
    else
    end
    event:Accept();
end

function TextArea:OnMouseMove(event)
    if (not self.__mouse_down__) then return end
    local sx, sy = event:GetXY()
    if (not self:Contain(sx, sy) or not event:IsLeftButtonPressed()) then return end

    self:SetCursorByPos(sx, sy);
    if (self.__selected_start_at__ == 0) then self.__selected_start_at__, self.__selected_start_lineindex__ = self.__cursor_at__, self.__cursor_lineindex__ end
    self.__selected_end_at__, self.__selected_end_lineindex__ = self.__cursor_at__, self.__cursor_lineindex__;

    self:AdjustSelectedXY();
    event:Accept();
end

function TextArea:OnMouseUp(event)
    self:ReleaseMouse();
    self.__mouse_down__ = false;
    if (not self:IsSelected()) then 
        self:ClearSelected() 
    else 
        -- print(string.format("__selected_start_lineindex__ = %s, __selected_start_at__ = %s, __selected_start_x__ = %s, __selected_start_y__ = %s", self.__selected_start_lineindex__, self.__selected_start_at__, self.__selected_start_x__, self.__selected_start_y__));
        -- print(string.format("__selected_end_lineindex__ = %s, __selected_end_at__ = %s, __selected_end_x__ = %s, __selected_end_y__ = %s", self.__selected_end_lineindex__, self.__selected_end_at__, self.__selected_end_x__, self.__selected_end_y__));
    end 
    event:Accept();
end


function TextArea:OnKeyDown(event)
    if (not self:IsFocus() or self:IsDisabled() or self:IsReadOnly()) then return end
	if (KeyBoard:IsKeyPressed(KeyBoard.VK_RETURN)) then self:handleReturn() 
	elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_ESCAPE)) then self:handleEscape()
	elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_BACKSPACE)) then self:handleBackspace()
    elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_DELETE)) then self:handleDelete()
	elseif (KeyBoard:IsCtrlKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_Z)) then self:handleUndo()
	elseif (KeyBoard:IsCtrlKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_Y)) then self:handleRedo()
	elseif (KeyBoard:IsCtrlKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_A)) then self:HandleSelectAll()
	elseif (KeyBoard:IsCtrlKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_C)) then self:handleCopy()
	elseif (KeyBoard:IsCtrlKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_V)) then self:handlePaste()
	elseif (KeyBoard:IsCtrlKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_X)) then self:handleCut()
	elseif (KeyBoard:IsShiftKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_UP)) then self:handleSelectPrevLine()
	elseif (KeyBoard:IsShiftKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_RIGHT)) then self:handleSelectNextChar()
	elseif (KeyBoard:IsShiftKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_DOWN)) then self:handleSelectNextLine()
	elseif (KeyBoard:IsShiftKeyPressed() and KeyBoard:IsKeyPressed(KeyBoard.VK_LEFT)) then self:handleSelectPrevChar()
    elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_HOME)) then self:handleMoveHome()
    elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_END)) then self:handleMoveEnd()
	elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_UP)) then self:handleMoveToPrevLine()
	elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_RIGHT)) then self:handleMoveToNextChar()
	elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_DOWN)) then self:handleMoveToNextLine()
	elseif (KeyBoard:IsKeyPressed(KeyBoard.VK_LEFT)) then self:handleMoveToPrevChar()
    else
	end
end

function TextArea:IsReadOnly()
    return self:GetAttrBoolValue("readonly");
end

function TextArea:OnChar(event)
    if (not self:IsFocus() or self:IsDisabled() or self:IsReadOnly()) then return end

    -- 输入串
    local char = event:GetChar();

    -- 忽略控制字符
    local charcode = string.byte(char, 1);
    -- print("Input:OnChar", char, string.len(char), charcode);

    if(charcode <= 31) then return end

    -- 添加新文本
    self:InsertTextCmd(char);
end


function TextArea:InsertTextCmd(text, startAt)
    if (not text or text == "") then return end
    -- 先删除已选择的文本
    if (self:IsSelected()) then 
        local __selected_start_at__ = self:GetSelected();
        self:DeleteSelected();
        self.__cursor_at__ = __selected_start_at__;
    end

    startAt = math.min(startAt or self.__cursor_at__, self:GetTextLength() + 1);
    local textLength = commonlib.ustring(text):len();
    local endAt = startAt + textLength - 1;
    table.insert(self.__undo_cmds__, {startAt = startAt, endAt = endAt, action = "insert", text = text});
    -- print(string.format("InsertTextCmd before cursorAt = %s, startAt = %s, endAt = %s, text = %s", self.cursorAt, startAt, endAt, self:GetValue()));
    self:InsertText(startAt, endAt, text);
    -- print(string.format("InsertTextCmd after cursorAt = %s, startAt = %s, endAt = %s, text = %s", self.cursorAt, startAt, endAt, self:GetValue()));
end

function TextArea:InsertText(startAt, endAt, text)
    self.__text__:insert(startAt, text);
    self:UpdateLineInfo();
    self:OnChange();
    if (startAt <= self.__cursor_at__) then self:AdjustCursor(endAt - startAt + 1) end
end

function TextArea:DeleteSelected()
    if (not self:IsSelected()) then return end
    local selectStartAt, selectEndAt = self:GetSelected();
    self:DeleteTextCmd(selectStartAt, selectEndAt - selectStartAt);
    self:ClearSelected();
end

function TextArea:DeleteTextCmd(startAt, count)
    if (not startAt or not count or count == 0) then return end
    local endAt = startAt + count - 1;
    if (endAt < startAt) then startAt, endAt = endAt, startAt end
    if (endAt < 1) then return end
    startAt = math.max(startAt, 1);
    table.insert(self.__undo_cmds__, {startAt = startAt, endAt = endAt, action = "delete", text = self.__text__:sub(startAt, endAt):tostring()});
    -- commonlib.print_format("DeleteTextCmd before cursorAt = %s, startAt = %s, endAt = %s, text = %s", self.cursorAt, startAt, endAt, self:GetValue());
    self:DeleteText(startAt, endAt);
    -- commonlib.print_format("DeleteTextCmd after cursorAt = %s, startAt = %s, endAt = %s, text = %s", self.cursorAt, startAt, endAt, self:GetValue());
end

function TextArea:DeleteText(startAt, endAt)
    local count = endAt - startAt + 1;
    self.__text__:remove(startAt, count);
    self:UpdateLineInfo();
    if (self.__cursor_at__ <= startAt) then
    elseif (self.__cursor_at__ >= endAt) then self:AdjustCursor(-count)
    else self:AdjustCursor(startAt - self.__cursor_at__) end 
    self:OnChange();
end

-- 调整光标的位置, 调整前文本需完整, 因此添加需先添加后调整光标, 移除需先调整光标后移除
function TextArea:AdjustCursor(offset)
    -- commonlib.print_format("AdjustCursor Before cursorAt = %s, cursorX = %s, lineindex = %s, text = %s", self.__cursor_at__, self.__cursor_x__, self.__cursor_lineindex__, self.__text__:tostring());
    if (not offset or offset == 0) then return end
    -- 保存光标位置的正确性 调整 offset 
    local cursorAt, maxAt = self.__cursor_at__ + offset, self.__text__:len() + 1;
    local lastCursorX, lastCursorLine = self.__cursor_x__, self.__cursor_lineindex__;
    if (cursorAt > maxAt) then offset = maxAt - self.__cursor_at__ end
    if (cursorAt < 1) then offset = 1 - self.__cursor_at__ end
    if (offset == 0) then return end

    self.__cursor_at__ = self.__cursor_at__ + offset;
    for i, line in ipairs(self.__lines__) do
        if (line.__start_at__ <= self.__cursor_at__ and self.__cursor_at__ <= line.__end_at__) then
            self.__cursor_lineindex__ = i;
            self.__cursor_x__ = self:GetTextWidth(self.__text__:sub(line.__start_at__, self.__cursor_at__ - 1):tostring());
            break;
        end
    end
    if (self.__cursor_lineindex__ > (self.__offset_y_line_count__ + self.__view_max_line_count__)) then
        self.__offset_y_line_count__ = self.__cursor_lineindex__ - self.__view_max_line_count__;
        self.__offset_y__ = self.__offset_y_line_count__ * self:GetLineHeight();
    end
    if (self.__cursor_lineindex__ <= self.__offset_y_line_count__) then
        self.__offset_y_line_count__ = self.__cursor_lineindex__ - 1;
        self.__offset_y__ = self.__offset_y_line_count__ * self:GetLineHeight();
    end

    if (self.__cursor_x__ > self.__view_max_width__) then
        if (lastCursorLine == self.__cursor_lineindex__) then
            self.__offset_x__ = self.__offset_x__ + self.__cursor_x__ - lastCursorX;
        else
            self.__offset_x__ = self.__cursor_x__ - self.__view_max_width__;
        end
    else
        self.__offset_x__ = 0;
    end

    self:OnCursorChange();
    -- commonlib.print_format("AdjustCursor Before cursorAt = %s,cursorX = %s, lineindex = %s, text = %s", self.__cursor_at__, self.__cursor_x__,  self.__cursor_lineindex__, self.__text__:tostring());
end

function TextArea:OnCursorChange()
    local x, y, w, h = self:GetPosition();

    x = x - self.__offset_x__;
    y = y - self.__offset_y__;

    local sx, sy = self:ElementXYToScreenXY(x + self.__cursor_x__, y + (self.__cursor_lineindex__ - 1) * self:GetLineHeight());
    commonlib.SetTextInputPosition(sx, sy);
end

function TextArea:OnChange()
    self:CallAttrFunction("onchange", nil, self:GetValue());
end

function TextArea:handleReturn()
    self:InsertTextCmd("\n");
end

function TextArea:handleEscape()
    self:FocusOut();
end

function TextArea:handleBackspace()
    if (self:IsSelected()) then
        self:DeleteSelected();
    else
        self:DeleteTextCmd(self.__cursor_at__ - 1, 1);
    end
end

function TextArea:handleDelete()
    if (self:IsSelected()) then
        self:DeleteSelected();
    else
        self:DeleteTextCmd(self.__cursor_at__, 1);
    end
end

function TextArea:handleUndo()
    if (#self.__undo_cmds__ == 0) then return end
    local len = #self.__undo_cmds__;
    local cmd = self.__undo_cmds__[len];
    table.remove(self.__undo_cmds__, len);
    table.insert(self.__redo_cmds__, cmd);
    if (cmd.action == "insert") then
        self:DeleteText(cmd.startAt, cmd.endAt);
    elseif (cmd.action == "delete") then
        self:InsertText(cmd.startAt, cmd.endAt, cmd.text);
    end
end

function TextArea:handleRedo()
    if (#self.__redo_cmds__ == 0) then return end
    local len = #self.__redo_cmds__;
    local cmd = self.__redo_cmds__[len];
    table.remove(self.__redo_cmds__, len);
    table.insert(self.__undo_cmds__, cmd);
    if (cmd.action == "insert") then
        self:InsertText(cmd.startAt, cmd.endAt, cmd.text);
    elseif (cmd.action == "delete") then
        self:DeleteText(cmd.startAt, cmd.endAt);
    end
end

function TextArea:HandleSelectAll()
    self.__selected_start_at__, self.__selected_end_at__ = 1, self.__text__:len() + 1;
    self:AdjustSelectedXY();
end

function TextArea:handleSelectWorld()
    -- local beginPos, endPos = self:GetText():wordPosition(self.cursorAt);
    -- self.selectStartAt, self.selectEndAt = beginPos + 1, endPos;
end

function TextArea:handleCopy()
    if (not self:IsSelected()) then return end
    local selectedText = self:GetSelectedText();
    commonlib.SetClipboardText(selectedText);
end

function TextArea:handleCut()
    self:handleCopy();
    self:DeleteSelected();
end

function TextArea:handlePaste()
    local clip_text = commonlib.GetClipboardText();
    self:InsertTextCmd(clip_text)
end

function TextArea:handleMoveHome(bselected)
    if (bselected) then
        self.__selected_start_at__ = 1;
        self.__selected_end_at__ = self.__cursor_at__;
        self:AdjustSelectedXY();
    else
        self:AdjustCursor(- self.__cursor_at__ + 1);
    end
    self:ResetCursor();
end

function TextArea:handleMoveEnd(event, bselected)
    if (bselected) then
        self.__selected_start_at__ = self.cursorAt;
        self.__selected_end_at__ = self:GetTextLength() + 1;
        self:AdjustSelectedXY();
    else
        self:AdjustCursor(self:GetTextLength() + 1 + 1 - self.__cursor_at__);
    end
    self:ResetCursor();
end

function TextArea:handleMoveToNextChar()
    self:ClearSelected();
    self:AdjustCursor(1);
    self:ResetCursor();
end

function TextArea:handleMoveToPrevChar()
    self:ClearSelected();
    self:AdjustCursor(-1);
    self:ResetCursor();
end

function TextArea:handleSelectNextChar()
    if (self.__selected_start_at__ == 0) then
        self.__selected_start_at__ = self.__cursor_at__;
        self.__selected_start_lineindex__ = self.__cursor_lineindex__;
        self.__selected_start_x__ = self.__cursor_x__;
        self.__selected_start_y__ = (self.__selected_start_lineindex__ - 1) * self:GetLineHeight();
    end
    self:AdjustCursor(1);
    self.__selected_end_at__ = self.__cursor_at__;
    self.__selected_end_lineindex__ = self.__cursor_lineindex__;
    self.__selected_end_x__ = self.__cursor_x__;
    self.__selected_end_y__ = (self.__selected_end_lineindex__ - 1) * self:GetLineHeight();
    -- print("Input:handleSelectNextChar", self.selectStartAt, self.selectEndAt, self.selectStartX, self.selectEndX)
end

function TextArea:handleSelectPrevChar()
    if (self.__selected_start_at__ == 0) then
        self.__selected_start_at__ = self.__cursor_at__;
        self.__selected_start_lineindex__ = self.__cursor_lineindex__;
        self.__selected_start_x__ = self.__cursor_x__;
        self.__selected_start_y__ = (self.__selected_start_lineindex__ - 1) * self:GetLineHeight();
    end
    self:AdjustCursor(-1);
    self.__selected_end_at__ = self.__cursor_at__;
    self.__selected_end_lineindex__ = self.__cursor_lineindex__;
    self.__selected_end_x__ = self.__cursor_x__;
    self.__selected_end_y__ = (self.__selected_end_lineindex__ - 1) * self:GetLineHeight();
    -- print("Input:handleSelectPrevChar", self.selectStartAt, self.selectEndAt, self.selectStartX, self.selectEndX)
end

function TextArea:handleMoveToPrevLine()
    if (self.__cursor_lineindex__ == 1) then return end 
    local prev_line = self.__lines__[self.__cursor_lineindex__ - 1];
    local cursor_line = self.__lines__[self.__cursor_lineindex__];
    local offset_x = self.__cursor_at__ - cursor_line.__start_at__;
    local cursor_at = math.min(prev_line.__start_at__ +offset_x, prev_line.__end_at__);
    self:AdjustCursor(cursor_at - self.__cursor_at__);
    self:ResetCursor();
end

function TextArea:handleMoveToNextLine()
    if (self.__cursor_lineindex__ >= (#self.__lines__)) then return end 
    local next_line = self.__lines__[self.__cursor_lineindex__ + 1];
    local cursor_line = self.__lines__[self.__cursor_lineindex__];
    local offset_x = self.__cursor_at__ - cursor_line.__start_at__;
    local cursor_at = math.min(next_line.__start_at__ +offset_x, next_line.__end_at__);
    self:AdjustCursor(cursor_at - self.__cursor_at__);
    self:ResetCursor();
end

function TextArea:handleSelectPrevLine()
    if (self.__selected_start_at__ == 0) then
        self.__selected_start_at__ = self.__cursor_at__;
        self.__selected_start_lineindex__ = self.__cursor_lineindex__;
        self.__selected_start_x__ = self.__cursor_x__;
        self.__selected_start_y__ = (self.__selected_start_lineindex__ - 1) * self:GetLineHeight();
    end
    self:handleMoveToPrevLine();
    self.__selected_end_at__ = self.__cursor_at__;
    self.__selected_end_lineindex__ = self.__cursor_lineindex__;
    self.__selected_end_x__ = self.__cursor_x__;
    self.__selected_end_y__ = (self.__selected_end_lineindex__ - 1) * self:GetLineHeight();
    -- print("Input:handleSelectPrevChar", self.selectStartAt, self.selectEndAt, self.selectStartX, self.selectEndX)
end

function TextArea:handleSelectNextLine()
    if (self.__selected_start_at__ == 0) then
        self.__selected_start_at__ = self.__cursor_at__;
        self.__selected_start_lineindex__ = self.__cursor_lineindex__;
        self.__selected_start_x__ = self.__cursor_x__;
        self.__selected_start_y__ = (self.__selected_start_lineindex__ - 1) * self:GetLineHeight();
    end
    self:handleMoveToNextLine();
    self.__selected_end_at__ = self.__cursor_at__;
    self.__selected_end_lineindex__ = self.__cursor_lineindex__;
    self.__selected_end_x__ = self.__cursor_x__;
    self.__selected_end_y__ = (self.__selected_end_lineindex__ - 1) * self:GetLineHeight();
    -- print("Input:handleSelectNextChar", self.selectStartAt, self.selectEndAt, self.selectStartX, self.selectEndX)
end

function TextArea:handleMoveToNextWord()
end
function TextArea:handleMoveToPrevWord()
end
function TextArea:handleSelectNextWord()
end
function TextArea:handleSelectPrevWord()
end

return TextArea;
